grammar OwlServerQL;

options {
	language=CSharp3;
	backtrack=true;
}

@lexer::header {
	using System.Collections;
	using OWLServerQL.dominio;
}

@lexer::members {
	private int numErrors = 0;
	private IList<ErrorOwlServerLQ> errores = new List<ErrorOwlServerLQ>();

	public override string GetErrorMessage(RecognitionException e, string[] tokenNames)
	{
		numErrors++;
		string msg = base.GetErrorMessage(e,tokenNames);
		
		errores.Add(new ErrorOwlServerLQ(msg, e.Line, e.CharPositionInLine));
		
		return msg;
	}
	
	public int NumErrors
	  {
	      get { return numErrors; }
	      private set { numErrors = value; }
	  }
	  
	  public IList<ErrorOwlServerLQ> Errores
	  {
	      get { return errores; }
	      private set { errores = value; }
	  }
}

@header {
	using OWLServerQL.dominio;
	using System;
	using System.Collections;
}

@members {
	private Consulta consultaFinal;
	private int numErrors = 0;
	private IList<ErrorOwlServerLQ> errores = new List<ErrorOwlServerLQ>();
	private List<Elemento> subConsultas = new List<Elemento>();
  
  public Consulta ConsultaFinal
  {
      get { return consultaFinal; }
      private set { consultaFinal = value; }
  }
  
  public int NumErrors
  {
      get { return numErrors; }
      private set { numErrors = value; }
  }
  
  public IList<ErrorOwlServerLQ> Errores
  {
      get { return errores; }
      private set { errores = value; }
  }

	public override string GetErrorMessage(RecognitionException e, string[] tokenNames)
	{
		numErrors++;
		string msg = base.GetErrorMessage(e,tokenNames);
		
		errores.Add(new ErrorOwlServerLQ(msg, e.Line, e.CharPositionInLine));
		
		return msg;
	}
	
	public Elemento concatenaConsulta(Elemento elem)
        {
            if (subConsultas.Count > 0)
            {
                Elemento elementoActual = elem;
                foreach (Elemento el in subConsultas)
                {
                    elementoActual.ElementoSiguiente = el;
                    elementoActual = el;
                }
            }

            return elem;
        }
}

SELECT : ('S' | 's') ('E'|'e') ('L'|'l') ('E'|'e') ('C'|'c') ('T'|'t');
INDIVIDUALS : ('I'|'i') ('N'|'n') ('D'|'d') ('I'|'i') ('V'|'v') ('I'|'i') ('D'|'d') ('U'|'u') ('A'|'a') ('L'|'l') ('S'|'s');
WHERE : ('W'|'w') ('H'|'h') ('E'|'e') ('R'|'r') ('E'|'e');
CLASS : ('C'|'c') ('L'|'l') ('A'|'a') ('S'|'s') ('S'|'s');
AS : ('A'|'a') ('S'|'s');
OBJECT : ('O'|'o') ('B'|'b') ('J'|'j') ('E'|'e') ('C'|'c') ('T'|'t');
PROPERTY : ('P'|'p') ('R'|'r') ('O'|'o') ('P'|'p') ('E'|'e') ('R'|'r') ('T'|'t') ('Y'|'y');
DATATYPE : ('D'|'d') ('A'|'a') ('T'|'t') ('A'|'a') ('T'|'t') ('Y'|'y') ('P'|'p') ('E'|'e');
NOT : ('N'|'n') ('O'|'o') ('T'|'t');
AND : ('A'|'a') ('N'|'n') ('D'|'d');
OR : ('O'|'o') ('R'|'r');
SAME : ('S'|'s') ('A'|'a') ('M'|'m') ('E'|'e');
DISTINCT : ('D'|'d') ('I'|'i') ('S'|'s') ('T'|'t') ('I'|'i') ('N'|'n') ('C'|'c') ('T'|'t');
ALL : ('A'|'a') ('L'|'l') ('L'|'l');
FROM : ('F' | 'f') ('R' | 'r') ('O' | 'o') ('M' | 'm');

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=Hidden;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=Hidden;}
    ;

WS : (' '|'\r'|'\n'|'\t')+ {$channel=Hidden;} ;

LITERAL
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;


// Reglas de sintaxis
public
inicio_consulta: SELECT INDIVIDUALS cs=consulta FROM LITERAL ';' { this.ConsultaFinal = new Consulta(cs, $LITERAL.Text.Replace("\"","")); };

tipo_consulta returns [Elemento e] : cl=clases {e = cl; } | po=p_objetos {e = po; } 
                                    | pd=p_datos {e = pd; } | ia=igual_a {e = ia; } | dd=distinto_de {e = dd; };

consulta returns [Elemento e] : tc=tipo_consulta (rc=resto_consulta | ) { tc.ElementoSiguiente = rc; e = tc; }
                    		| '(' cs=consulta ')' (rc=resto_consulta | ) { ConjuntoElementos cjt = new ConjuntoElementos (cs); cjt.ElementoSiguiente = rc; e = cjt; };
                    
resto_consulta returns [Elemento e] : AND cs=consulta { cs.UnionAnterior = TipoUnion.AND; e = cs; } 
                                                    | OR cs=consulta { cs.UnionAnterior = TipoUnion.OR; e = cs; };

comparadores returns [TipoComparacion tc] : '=' {tc = TipoComparacion.IGUAL;} | '!=' {tc = TipoComparacion.DISTINTO; }
						| '>' {tc = TipoComparacion.MAYOR_QUE;} | '<' {tc = TipoComparacion.MENOR_QUE; }
						| '>=' {tc = TipoComparacion.MAYOR_IGUAL_QUE;} | '<=' {tc = TipoComparacion.MENOR_IGUAL_QUE; };

literales returns [ElementoLiteral e] : NOT LITERAL { e = new ElementoLiteral($LITERAL.Text.Replace("\"",""), true); } 
					| LITERAL { e = new ElementoLiteral($LITERAL.Text.Replace("\"",""), false); } 
					| ALL { e = new ElementoLiteral(); };
					
comparacion returns [ElementoComparador e] : li1=LITERAL comp=comparadores li2=LITERAL { e = new ElementoComparador(li1.Text.Replace("\"",""), li2.Text.Replace("\"",""), comp, false); }
                    | NOT li1=LITERAL comp=comparadores li2=LITERAL { e = new ElementoComparador(li1.Text.Replace("\"",""), li2.Text.Replace("\"",""), comp, true); }
                    | ALL comp=comparadores li2=LITERAL { e = new ElementoComparador(null, li2.Text.Replace("\"",""), comp, false); }
                    | li1=LITERAL comp=comparadores ALL { e = new ElementoComparador(li1.Text.Replace("\"",""), null, comp, false); };

clases returns [Elemento e] : WHERE CLASS AS cj=conjunto_literales { e = new ConjuntoElementos(cj, TipoElemento.CLASS); } ;

igual_a returns [Elemento e] : SAME AS cj=conjunto_literales { e = new ConjuntoElementos(cj, TipoElemento.SAME_AS); };

distinto_de returns [Elemento e] : DISTINCT cj=conjunto_literales { e = new ConjuntoElementos(cj, TipoElemento.DISTINCT); };

conjunto_literales returns [Elemento e] : li=literales (rc=resto_conjunto | ) { li.ElementoSiguiente = rc; e = li; }
		                    	| '(' cj=conjunto_literales ')' (rc=resto_conjunto | ) { ConjuntoElementos cjt = new ConjuntoElementos (cj); cjt.ElementoSiguiente = rc; e = cjt; };
                    
resto_conjunto returns [Elemento e] : AND cj=conjunto_literales { cj.UnionAnterior = TipoUnion.AND; e = cj; }
                          | OR cj=conjunto_literales { cj.UnionAnterior = TipoUnion.OR; e = cj; };

p_objetos returns [Elemento e] : WHERE OBJECT PROPERTY AS cj=conjunto_comparaciones { e = new ConjuntoElementos(cj, TipoElemento.PROPIEDADES_OBJETO); };

p_datos returns [Elemento e] : WHERE DATATYPE PROPERTY AS cj=conjunto_comparaciones { e = new ConjuntoElementos(cj, TipoElemento.PROPIEDADES_DATO); };

conjunto_comparaciones returns [Elemento e] : cp=comparacion (rc=resto_conjunto_comparaciones | ) { cp.ElementoSiguiente = rc; e = cp; }
                    				| '(' cj=conjunto_comparaciones ')' (rc=resto_conjunto_comparaciones | ) { ConjuntoElementos cjt = new ConjuntoElementos (cj); cjt.ElementoSiguiente = rc; e = cjt; };
                    
resto_conjunto_comparaciones returns [Elemento e] : AND cj=conjunto_comparaciones { cj.UnionAnterior = TipoUnion.AND; e = cj; } 
                                                    | OR cj=conjunto_comparaciones { cj.UnionAnterior = TipoUnion.OR; e = cj; };